using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using WebApplication;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Xml.XPath;

namespace WebApplication
{
	/// <summary>
	/// Summary description for PrivateSales.
	/// </summary>
	public partial class PrivateSales : System.Web.UI.Page
	{

		private void InitializeAuctionPriority ()  // This function may have to be rewritten.
		{
			Game	game = Global.getGame (this);;
			int		nHighbid = 0;

// Auction priority goes to the left of the player with the high bid.

			foreach (Bid bid in game.CurrentInAuctionBids)
			{
				if (bid.Amount > nHighbid)
				{
					game.AuctionPriorityPlayerName = bid.Player;	// Temporarily give the player with the highest bid the priority.
					nHighbid = bid.Amount;
				}
			}
		
//			GivePriorityToNextPlayer ();	//	Player to the left of the high bid.  This will be called later.  For now, leave the priority with the highest bid.
		}

		private void GivePriorityToNextPlayer ()
		{
			Game game = Global.getGame (this);

			int		i = 0;
			bool	bGiveNextPlayerPriority = false;

			if (game.AuctionPhase)  // See if the player has an active bid otherwise she should be skipped.
			{
				foreach (Bid bid in game.CurrentInAuctionBids)
				{
					if (bGiveNextPlayerPriority)
					{
						game.AuctionPriorityPlayerName = bid.Player;
						bGiveNextPlayerPriority = false;
						break;
					}
					else
					{
						if (bid.Player == game.AuctionPriorityPlayerName)
						{
							bGiveNextPlayerPriority = true;
						}
					}
				}

				if (bGiveNextPlayerPriority == true)
				{
					Bid priorityBid = game.CurrentInAuctionBids[0];
					game.AuctionPriorityPlayerName = priorityBid.Player;
				}
			} 
			else
			{
				Player nextPlayer;

				foreach (Player player in game.Players)
				{
					if (player.Priority)
					{
						player.Priority = false;
						break;
					}
					else
					{
						i++;
					}
				}

				i++;  // The player with priority is the one after the current one.

				if (i < game.Players.Count)
				{
					nextPlayer = (Player) game.Players[i];
				}
				else // back to the first player.
				{
					nextPlayer = (Player) game.Players[0];
				}

				nextPlayer.Priority = true;
			}

			game.SaveGame ("");  //JWF 10.12.07
		}

		private void DisplayError (string sError)
		{
			bidError.Text = sError;
			bidError.Visible = true;
		}

		private void DisplayMessage (string sMessage)
		{
			bidError.ForeColor = Color.Black;
			bidError.Text = sMessage;
			bidError.Visible = true;
		}

		protected void Page_Load(object sender, System.EventArgs e)
		{
// Randomly generate seating order and the priority.  Only the game's creator needs to do this.

			Game game = Global.getGame (this);

            if (game == null)
            {
                return;
            }

//            string sPlayer = Session["PlayerName"].ToString();  // JWF 10.12.07
            string sPlayer = "";
            
            object o = Session["PlayerName"];

            if (o != null)
            {
                sPlayer = o.ToString();
            }

/*  Just wanted to try Request and QueryString for the heck of it.
			string sPlayerName = this.Request.QueryString ["PlayerName"];
			bidError.Text = sPlayerName;
			bidError.Visible = true;
*/

// Only do this once to set the priority and seating order of the players.
			SetTitle(sPlayer);

			if (!IsPostBack)
			{
				if (!game.Initialized)
				{
				    game.Initialized = true;
					int nPlayersStartingCash = game.StartingCapital / game.Players.Count;
					Random random = new Random (unchecked ((int)DateTime.Now.Ticks)); 

					for (int i = 0; i < game.Players.Count; i++)
					{
						int nNextPlayer = random.Next (game.Players.Count);

						Player temp = game.Players[i] as Player;
						game.Players[i] = game.Players[nNextPlayer];
						game.Players[nNextPlayer] = temp;
					}

					for (int i = 0; i < game.Players.Count; i++)
					{
						Player player = (Player) game.Players[i];
						player.Cash = nPlayersStartingCash;
						player.AvailableCash = nPlayersStartingCash;
					}

					Player priorityPlayer = (Player) game.Players[0];
					priorityPlayer.Priority = true;
//					game.Creator = "";   // JWF 10.13.2007  For reloading a saved game want the creators to be the same.


					game.History.Add ("Game started");
				}
			}

//            if (0 == game.Creator.Length)  // Game has started, no longer need a creator   JWF 10.13.2007
            if (game.Started)  // Game has started, no longer need a creator
			{
				FillPrivateTable ();
				FillPlayerTable ();
				SetBuyButtonToNextCompanyToPurchaseOutright ();
				Passes.Text = game.Passes + " passes";
				historyLB.DataSource = game.History;
				historyLB.DataBind ();
				historyLB.SelectedIndex = historyLB.Items.Count - 1;
			}

			if (game.AuctionPhase)
			{
				string		sMessage;
				Bid			priorityBid = game.CurrentInAuctionBids[0];

				sMessage = "Auction for: " + priorityBid.CompanyName;
				this.DisplayMessage (sMessage);
			}
		}

		private void SetTitle (string sNewTitle)
		{
			HtmlGenericControl title = this.FindControl ("Title") as HtmlGenericControl;

			if (title != null)
				title.InnerText = sNewTitle;
		}

		private void RefreshAllPages ()  // Is there a better way to do this?
		{
			Server.Transfer ("PrivateSales.aspx");   // Update my screen.
		}
		
		private void SetBuyButtonToNextCompanyToPurchaseOutright ()
		{
			Game game = Global.getGame (this);
	
			if (game.PrivateCompanies.Count > 0)
			{
				string sCompany;

				sCompany = game.PrivateCompanies[0].Name;
				pbBuy.Text = "Buy: " + sCompany + " at cost: " + game.PrivateCompanies[0].Cost;
			}
			else  // Nothing left to buy, the initial round is over.  Go to the 1st stock round.
			{
				pbBuy.Text = "Nothing left to purchase - Go to stock round.";
				pbBuy.Enabled = false; 

				game.History.Clear ();
				game.History.Add ("Stock Round");
				game.Passes = 0;
				Response.Redirect("StockRound.aspx");
			}
		}

		private void EnableControls (bool bEnable)
		{
			Game game = Global.getGame (this);

			if (game.AuctionPhase == false)
			{
				pbBuy.Enabled = bEnable;
				editCompanyBidOn.Enabled = bEnable;
			}
			else
			{
				pbBuy.Enabled = false;
				editCompanyBidOn.Enabled = false;
				editCompanyBidOn.Text = "1";
			}

			 pbPass.Enabled = bEnable;
			 pbBid.Enabled = bEnable;
			 editAmountBid.Enabled = bEnable;
			 PriorityCheckBox.Enabled = false;

// Disable refresh for the current player's turn.  Client side script will handle turning on/off the refresh.

			if (bEnable)
			{
			    currentPlayersTurn.ForeColor = Color.DarkGreen;
				PriorityCheckBox.Checked = true;
			}
			else
			{
                currentPlayersTurn.ForeColor = Color.Red;
                PriorityCheckBox.Checked = false;
			}
		}

		private void FillPrivateTable ()
		{
			Game game = Global.getGame (this);
			int nIndex = 1;

			foreach (PrivateCompany privateCompany in game.PrivateCompanies)
			{
				string sCompanyName;
				string sCost;
				string sIncome;
				string sHighBid;

				sHighBid = "";
				sCompanyName = privateCompany.Name;
				sCost = privateCompany.Cost.ToString ();
				sIncome = privateCompany.Income.ToString ();

				if (privateCompany.LastBid > 0)
				{
					sHighBid = privateCompany.LastBid.ToString ();
				}

				TableRow row = new TableRow ();
				TableCell cell = new TableCell ();
				cell.Text = nIndex + ": " + sCompanyName;
				row.Cells.Add (cell);

				TableCell cell2 = new TableCell ();
				cell2.Text = "$" + sCost;
				row.Cells.Add (cell2);

				TableCell cell3 = new TableCell ();
				cell3.Text = "$" + sIncome;
				row.Cells.Add (cell3);

				if (sHighBid.Length > 0)
				{
					TableCell cell4 = new TableCell ();
					cell4.Text = "$" + sHighBid;
					row.Cells.Add (cell4);
				}

				PrivatesTable.Rows.Add (row);
				nIndex++;
			}
		}

		private void FillPlayerTable ()
		{
			Game game = Global.getGame (this);
			string sPlayer = Session["PlayerName"].ToString ();

			foreach (Player player in game.Players)
			{
				TableRow row = new TableRow ();
				TableCell cell = new TableCell ();
				cell.Text = player.Name;

				if (player.Priority)
				{
					row.BackColor = System.Drawing.Color.Beige;
					cell.ForeColor = System.Drawing.Color.Red;
					cell.Font.Bold = true;
				}

				if (player.Name == sPlayer)
				{
					cell.Font.Italic = true;
//					cell.BackColor = System.Drawing.Color.Beige;
				}

				row.Cells.Add (cell);
				TableCell cell2 = new TableCell ();
				cell2.Text = player.Cash.ToString ();
				row.Cells.Add (cell2);

				TableCell cell3 = new TableCell ();
				cell3.Text = player.AvailableCash.ToString ();
				row.Cells.Add (cell3);

				TableCell cell4 = new TableCell ();
				string sPrivates;
				sPrivates = "";
				bool bFirst;
				bFirst = true;

				foreach (PrivateCompany privateCompany in player.PrivateCompanies)
				{
					if (bFirst)
					{
						sPrivates = privateCompany.Name;
						bFirst = false;
					}
					else
					{
						sPrivates += ", " + privateCompany.Name;
					}
				}

				cell4.Text = sPrivates;
				row.Cells.Add (cell4);

				bFirst = true;
				string sBids;
				sBids = "";

				foreach (Bid bid in game.Bids)
				{
					if (bid.Player == player.Name)
					{
						if (!bFirst)
						{
							sBids += ", ";
						}

						bFirst = false;

						sBids += bid.CompanyName;
						sBids += "(";
						sBids += bid.Amount;
						sBids += ")";
					}
				}

				TableCell cell5 = new TableCell ();
				cell5.Text = sBids;
				row.Cells.Add (cell5);

				PlayersTable.Rows.Add (row);

				if (game.AuctionPhase)
				{
					currentPlayersTurn.Text = game.AuctionPriorityPlayerName;

					if (sPlayer == game.AuctionPriorityPlayerName)
						EnableControls (true);
					else
						EnableControls (false);
				}
				else
				{
					if (player.Priority)
					{
						currentPlayersTurn.Text = player.Name;

						if (sPlayer == player.Name)
							EnableControls (true);
						else
							EnableControls (false);
					}
				}
			}
		}

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
		
			base.OnInit(e); 
		}
		
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    

		}
		#endregion


		void AddBid (Player player, Bid newBid, BidCollection bc)
		{
			string	sCompanyName = newBid.CompanyName;
			string	sPlayerName = newBid.Player;
			bool	bAdd = true;

			foreach (Bid bid in bc) 
			{
				if ((bid.CompanyName == newBid.CompanyName) && (bid.Player == newBid.Player))
				{
					player.AvailableCash += bid.Amount;  // Refund the old bid amount to the player.
					bAdd = false;
					bid.Amount = newBid.Amount;
					break;
				}
			}

			if (bAdd)
			{
				bc.Add (newBid);
			}
		}

		private bool ResolveBids ()
		{
			bool	bContinueResolvingBids = false;
			Game	game = Global.getGame (this);;


			if (0 == game.PrivateCompanies.Count)  // All the privates have been sold.
			{
				return bContinueResolvingBids;
			}

			PrivateCompany privateCompany = game.PrivateCompanies[0];

			if (privateCompany.LastBid != 0)  // There were bids on this company.  For now, just award to the highest bidder.  Fix it later.
			{
				bool bFirstBidOnThisCompany = true;

				while (game.CurrentInAuctionBids.Count > 0)
				{
					game.CurrentInAuctionBids.Remove(game.CurrentInAuctionBids[0]);
				}

				Bid highBid = null;

				foreach (Bid currentBid in game.Bids)
				{
					if (currentBid.CompanyName == privateCompany.Name)
					{
						game.CurrentInAuctionBids.Add (currentBid);

						if (bFirstBidOnThisCompany)
						{
							highBid = currentBid;
							bFirstBidOnThisCompany = false;
						}
						else
						{
							game.AuctionPhase = true;
							InitializeAuctionPriority ();  
						}
					}
				}

				if (bFirstBidOnThisCompany)  // Exception, should never happen if LastBid != 0
				{
					GameException e = new GameException ("Invalid bid logic.  No bids found for company bid on.  Should never happen.  Contact tech support.");
					throw (e);
				}

				if (!game.AuctionPhase)  // Only one player bid on this private
				{
					game.Bids.RemoveBidsOnThisCompany (privateCompany.Name);
					game.Players [highBid.Player].AvailableCash += highBid.Amount;  // This will be reduced when the private is purchased.
					game.NextPrivatePurchased (highBid.Player);
					bContinueResolvingBids = true;
				}
				else
				{
					bContinueResolvingBids = false;
				}
			}

			return bContinueResolvingBids;
		}

		private bool ValidBid ()
		{
			bool	bValid = true;
			string	sCompanyBidOn = editCompanyBidOn.Text;
			string	sAmountBid = editAmountBid.Text;
			int		nCompanyBidOn = 0;
			int		nAmountBid = 0;
			int		nMinBidCompany;
			int		nMaxBidCompany;

			Game	game = Global.getGame (this);;

			if (game.AuctionPhase)  
			{
				nMinBidCompany = 1;
				nMaxBidCompany = 1;
			}
			else
			{
				nMinBidCompany = 2;
				nMaxBidCompany = game.PrivateCompanies.Count;
			}

			if (sCompanyBidOn.Length > 0)
			{
				try
				{
					 bool bReturn = int.TryParse (sCompanyBidOn, out nCompanyBidOn);
					 
					 if (!bReturn)
					 {
                         this.DisplayError("Must enter a company number to bid on.");
                         bValid = false;
					 }
				}
				catch
				{
					this.DisplayError ("Must enter a company number to bid on.");
					bValid = false;
				}
			}
			else
			{
				this.DisplayError ("Must enter a company number to bid on.");
				bValid = false;
			}

			if (sAmountBid.Length > 0)
			{
				try
				{
					bValid = int.TryParse (sAmountBid, out nAmountBid);
                    this.DisplayError("Must enter an amount bid.");
                }
				catch
				{
					this.DisplayError ("Must enter an amount bid.");
					bValid = false;
				}
			}
			else
			{
				this.DisplayError ("Must enter an amount to bid.");
				bValid = false;
			}

			if (nCompanyBidOn < nMinBidCompany)
			{
				this.DisplayError ("Invalid company number, must be " + nMinBidCompany + " or greater");
				bValid = false;
			}
			else if (nCompanyBidOn > nMaxBidCompany)
			{
				this.DisplayError ("Invalid company number, must be less than: " + nMaxBidCompany);
				bValid = false;
			}

			if (bValid)	// Make sure the amount is correct.
			{
				PrivateCompany privateCompany = game.PrivateCompanies[nCompanyBidOn - 1];

				if (0 == privateCompany.LastBid)
				{
					privateCompany.LastBid = privateCompany.Cost;
				}

				if (nAmountBid >= privateCompany.LastBid + 5)
				{
					string	sPlayer;
					int		nPlayersLastBidOnThisCompany = 0;

					sPlayer = Session["PlayerName"].ToString ();
					Player player = game.Players [sPlayer];

					if (game.AuctionPhase)
					{
						foreach (Bid bid in game.CurrentInAuctionBids) 
						{
							if ((bid.CompanyName == privateCompany.Name) && (bid.Player == sPlayer))
							{
								nPlayersLastBidOnThisCompany = bid.Amount;
							}
						}
					}
					else
					{
						foreach (Bid bid in game.Bids) 
						{
							if ((bid.CompanyName == privateCompany.Name) && (bid.Player == sPlayer))
							{
								nPlayersLastBidOnThisCompany = bid.Amount;
							}
						}
					}

					if (nAmountBid > player.AvailableCash + nPlayersLastBidOnThisCompany)
					{
						bValid = false;
						this.DisplayError ("Amount bid: $" + nAmountBid + " exceeds amount of cash available: $" + player.AvailableCash);
					}
					else // It's a valid bid.
					{
						player.AvailableCash -= nAmountBid;
						privateCompany.LastBid = nAmountBid;

						Bid bid = new Bid ();
						bid.Amount = nAmountBid;
						bid.CompanyName = privateCompany.Name;
						bid.Player = sPlayer;

						if (game.AuctionPhase)
						{
							AddBid (player, bid, game.CurrentInAuctionBids);
							game.AuctionPhasePasses = 0;	// Reset passes to 0.
						}
						else
						{
							AddBid (player, bid, game.Bids);
						}

						string sBid;
						sBid = bid.Player + " bid $" + bid.Amount + " on " + bid.CompanyName;
						game.History.Add (sBid);
					}
				}
				else
				{
					bValid = false;
					this.DisplayError ("Invalid bid, must be at least $" + (privateCompany.LastBid + 5));
				}
			}

			return bValid;
		}


		private void NextPlayer ()
		{
			GivePriorityToNextPlayer ();
			EnableControls (false);
			this.RefreshAllPages ();
		}

		private void EverybodyPassed ()
		{
			Game	game = Global.getGame (this);;

			if (game.AuctionPhase)
			{
				Bid		highBid = null;

				foreach (Bid bid in game.CurrentInAuctionBids)
				{
					Player player = game.Players [bid.Player];
					player.AvailableCash += bid.Amount;
					game.Bids.Remove (bid);

					if (highBid == null)
					{
						highBid = bid;
					}
					else
					{
						if (highBid.Amount < bid.Amount)
						{
							highBid = bid;
						}
					}
				}

				game.NextPrivatePurchased (highBid.Player);
				game.AuctionPhase = false;

				// Resolve anymore bids

				while (ResolveBids ())
				{
				}
			}
			else
			{
				if (game.PrivateSold)
				{
					game.PayoutPrivates();
				}
				else  // Reduce price by $5 of the first private.
				{
					game.PrivateCompanies [0].Cost -= 5;

					if (game.PrivateCompanies [0].Cost <= 0)
					{
                        game.PrivateCompanies[0].Cost = 0;
                        
                        NextPlayer ();  // The next player will be given the private for $0.

						foreach (Player player in game.Players)
						{
							if (player.Priority)
							{
								game.NextPrivatePurchased (player.Name);
								break;
							}
						}
					}
				}
			}
		}


		protected void pbBid_Click(object sender, System.EventArgs e)
		{
			Game game = Global.getGame (this);

			if (ValidBid ())
			{
				game.Passes = 0; // Reset pass counter.
				NextPlayer ();
			}
		}
		protected void pbBuy_Click(object sender, System.EventArgs e)
		{
			Game game = Global.getGame (this);
			string sPlayer = Session["PlayerName"].ToString ();

			if (game.AuctionPhase == true)  
			{
				return;  // Should never reach here, button would be disabled.
			}

			game.Passes = 0; // Reset pass counter.
			game.NextPrivatePurchased (sPlayer);

			while (ResolveBids ())
			{
			}

			NextPlayer ();
		}

		protected void pbPass_Click(object sender, System.EventArgs e)
		{
			Game	game = Global.getGame (this);;
			string	sPlayer = Session["PlayerName"].ToString ();
			string	sPass;

			sPass = sPlayer + " passed";
			game.History.Add (sPass);

			if (game.AuctionPhase)
			{
				game.AuctionPhasePasses++;

				if (game.AuctionPhasePasses == game.CurrentInAuctionBids.Count - 1) // All but one player needs to pass.
				{
					game.AuctionPhasePasses = 0;
					EverybodyPassed ();
				}
			}
			else
			{
				game.Passes++;

				if (game.Passes == game.Players.Count) // Has everybody passed?
				{
					game.Passes = 0;
					EverybodyPassed ();
				}
			}

			NextPlayer ();
		}

	}
}
